package com.ms.orm.dboperator.service;

import com.alibaba.fastjson.JSON;
import com.ms.common.util.ReflectUtils;
import com.ms.common.util.StringUtils;
import com.ms.orm.conditions.AbstractWrapper;
import com.ms.orm.conditions.Wrapper;
import com.ms.orm.context.DefaultLittleOrmContext;
import com.ms.orm.dboperator.DbCommonUtil;
import com.ms.orm.dboperator.DbOperator;
import com.ms.orm.exception.BaseSqlException;
import com.ms.orm.meta.IPage;
import com.ms.orm.meta.PropertyAndColumnInfo;
import com.ms.orm.meta.SqlAndParams;
import com.ms.orm.util.MetaDataOperator;
import com.ms.orm.util.SqlGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ResolvableType;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.sql.ResultSet;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * @author .
 * DefaultBaseService 中的方法如果需要事务，子类需要覆盖其对应方法
 * 需要开启 基于 Ciglib 的代理，
 * @EnableAspectJAutoProxy(proxyTargetClass=true)
 * 如果不开启ciglib代理，即 proxyTargetClass = true,生成的代理类是 'com.sun.proxy.$Proxy25',是实现接口BaseService，无法转换为具体的子类行，比如 UserService类型
 *
 */
@Service
@Transactional
public abstract class BaseService<T> implements DbOperator<T> {

    @Autowired
    protected  JdbcTemplate jdbcTemplate;
    protected final Class<T> entityType;
    protected final String tableName;

    public BaseService(){
        //1、获取当前 实例对于的 Class
        ResolvableType type = ResolvableType.forClass(getClass());
        //ResolvableType type = ResolvableType.forClass(ReflectUtils.getUserClass(getClass()));
        //2、把type 转换为 DefaultBaseService 类型，获取第一个泛型参数 的Class类型，即 T对于的实际Class类型
        this.entityType = (Class<T>) type.as(BaseService.class).getGeneric(0).resolve();
        this.tableName = DefaultLittleOrmContext.getDefaultLittleOrmContext().getEntityAndTableInfo(entityType).getTableName();
    }

    @Override
    public T findById(Serializable id) {
        String sql = "SELECT * FROM " + tableName + " WHERE" + MetaDataOperator.getEntityIdColumnName(entityType) +"= ?";
        return jdbcTemplate.queryForObject(sql,  entityRowMapper(),new Object[]{id});
    }

    @Override
    public List<T> findAll() {
        String sql = "SELECT * FROM " + tableName;
        return jdbcTemplate.query(sql, entityRowMapper());
    }

    @Override
    public int deleteById(Serializable id) {
        String sql = "DELETE FROM " + tableName + " WHERE" + MetaDataOperator.getEntityIdColumnName(entityType) +"= ?";
        return jdbcTemplate.update(sql, id);
    }

    @Override
    public int save(T entity) {
        // 构建SQL语句并执行保存操作
        SqlAndParams sqlAndParams = SqlGenerator.generateInsertSql(entity);
        return jdbcTemplate.update(sqlAndParams.getSql(), sqlAndParams.getParams().toArray());
    }

    @Override
    public int updateById(T entity) {
        // 构建SQL语句并执行更新操作
        SqlAndParams sqlAndParams = SqlGenerator.generateUpdateSql(entity);
        return jdbcTemplate.update(sqlAndParams.getSql(), sqlAndParams.getParams().toArray());
    }

    /**
     * 通过id 删除
     * @param entity 实体对象
     * @return
     */
    @Override
    public int deleteById(T entity) {
        String sql = "DELETE FROM " + tableName + " WHERE" + MetaDataOperator.getEntityIdColumnName(entityType) +"= ?";
        //获取主键值
        Object pkValue = ReflectUtils.invokeMethod(MetaDataOperator.getEntityAndTableInfo(entityType).getPrimaryKey().getPropertyReadMethod(),entity);
        return jdbcTemplate.update(sql, pkValue);
    }

    /**
     * 通过 Map 删除
     * @param columnMap 表字段 map 对象
     * @return
     */
    @Override
    public int deleteByMap(Map<String, Object> columnMap) {
        SqlAndParams sqlAndParams = SqlGenerator.generateDeleteSqlByMap(entityType,columnMap);
        return jdbcTemplate.update(sqlAndParams.getSql(), sqlAndParams.getParams().toArray());
    }

    @Override
    public int delete(Wrapper<T> updateWrapper) {
        AbstractWrapper wrapper = (AbstractWrapper) updateWrapper;
        wrapper.setEntityClass(entityType);
        SqlAndParams sqlAndParams = SqlGenerator.generateDeleteSqlByUpdateWrapper(entityType,updateWrapper);
        return jdbcTemplate.update(sqlAndParams.getSql(), sqlAndParams.getParams().toArray());
    }

    @Override
    public int deleteBatchIds(Collection<?> idList) {
        SqlAndParams sqlAndParams = SqlGenerator.generateDeleteSqlByIds(entityType,idList);
        return jdbcTemplate.update(sqlAndParams.getSql(), idList.toArray());
    }

    @Override
    public int update(T entity, Wrapper<T> updateWrapper) {
        AbstractWrapper wrapper = (AbstractWrapper) updateWrapper;
        wrapper.setEntityClass(entityType);
        SqlAndParams sqlAndParams = SqlGenerator.generateUpdateSqlByBeanAndUpdateWrapper(entityType,entity,updateWrapper);
        return jdbcTemplate.update(sqlAndParams.getSql(), sqlAndParams.getParams().toArray());
    }


    @Override
    public List<T> selectBatchIds(Collection<? extends Serializable> idList) {
        SqlAndParams sqlAndParams = SqlGenerator.generateQuerySqlByIds(entityType,idList);
        return jdbcTemplate.query(sqlAndParams.getSql(),entityRowMapper(),idList.toArray());
    }

    @Override
    public List<T> selectByMap(Map<String, Object> columnMap) {
        SqlAndParams sqlAndParams = SqlGenerator.generateQuerySqlByMap(entityType,columnMap);
        return jdbcTemplate.query(sqlAndParams.getSql(),entityRowMapper(),sqlAndParams.getParams().toArray());
    }

    @Override
    public Long selectCount(Wrapper<T> queryWrapper) {
        AbstractWrapper wrapper = (AbstractWrapper) queryWrapper;
        wrapper.setEntityClass(entityType);
        SqlAndParams sqlAndParams = SqlGenerator.generateSelectCountSqlByWrapper(entityType,queryWrapper);
        return jdbcTemplate.queryForObject(sqlAndParams.getSql(),Long.class,sqlAndParams.getParams()!=null?sqlAndParams.getParams().toArray():null);
    }

    @Override
    public List<T> selectList(Wrapper<T> queryWrapper) {
        AbstractWrapper wrapper = (AbstractWrapper) queryWrapper;
        wrapper.setEntityClass(entityType);
        if(StringUtils.hasLength(queryWrapper.getSqlSelect())){
            return jdbcTemplate.query(queryWrapper.getFinalSql(),entityRowMapper(queryWrapper.getSqlSelect().split(",")),((AbstractWrapper<?, ?, ?>) queryWrapper).getParamNameValue().toArray());
        }else{
            return jdbcTemplate.query(queryWrapper.getFinalSql(),entityRowMapper(),((AbstractWrapper<?, ?, ?>) queryWrapper).getParamNameValue().toArray());
        }
    }

    @Override
    public List<Map<String, Object>> selectMaps(Wrapper<T> queryWrapper) {
        AbstractWrapper wrapper = (AbstractWrapper) queryWrapper;
        wrapper.setEntityClass(entityType);
        return jdbcTemplate.queryForList(queryWrapper.getFinalSql(),((AbstractWrapper<?, ?, ?>) queryWrapper).getParamNameValue().toArray());
    }

    @Override
    public  List<T> selectOneColumnList(Wrapper<T> queryWrapper){
        AbstractWrapper wrapper = (AbstractWrapper) queryWrapper;
        wrapper.setEntityClass(entityType);
        if(!StringUtils.hasLength(queryWrapper.getSqlSelect())){
            throw new BaseSqlException("【selectOneColumnList】must select one column!");
        }
        return jdbcTemplate.query(queryWrapper.getFinalSql(),oneColumnRowMapper(queryWrapper.getSqlSelect().split(",")),((AbstractWrapper<?, ?, ?>) queryWrapper).getParamNameValue().toArray());
    }

    /**
     * 根据 entity 对应数据库字段 条件，查询全部记录（分页）
     * page.current = 1 ,则查询总数，其他不再查询总数
     * @param page  分页查询
     * @param queryWrapper   实体对象封装操作类（可以为 null）
     * @param <P>
     * @return
     */
    @Override
    public <P extends IPage<T>> P selectPage(P page, Wrapper<T> queryWrapper){
        AbstractWrapper wrapper = (AbstractWrapper) queryWrapper;
        wrapper.setEntityClass(entityType);
        if(page.searchCount()){
            page.setTotal(this.selectCount(queryWrapper));
        }

        SqlAndParams sqlAndParams = SqlGenerator.generateQueryPageSqlByWrapper(page,queryWrapper);
        List<T> recordList;
        if(StringUtils.hasLength(queryWrapper.getSqlSelect())){
            //查询指定列
            recordList = jdbcTemplate.query(sqlAndParams.getSql(),entityRowMapper(queryWrapper.getSqlSelect().split(",")),sqlAndParams.getParams().toArray());
        }else{
            recordList = jdbcTemplate.query(sqlAndParams.getSql(),entityRowMapper(),sqlAndParams.getParams().toArray());
        }
        page.setRecords(recordList!=null?recordList: Collections.emptyList());
        return page;
    }


    /**
     * 根据 Wrapper 条件，查询全部记录（并翻页）
     * @param page 分页查询条件
     * @param queryWrapper 实体对象封装操作类
     * @param <P>
     * @return
     */
    @Override
    public <P extends IPage<Map<String, Object>>> P selectMapsPage(P page,Wrapper<T> queryWrapper){
        AbstractWrapper wrapper = (AbstractWrapper) queryWrapper;
        wrapper.setEntityClass(entityType);
        if(page.searchCount()){
            page.setTotal(this.selectCount(queryWrapper));
        }
        SqlAndParams sqlAndParams = SqlGenerator.generateQueryPageSqlByWrapper(page,queryWrapper);
        List<Map<String, Object>> recordList = jdbcTemplate.queryForList(sqlAndParams.getSql(),sqlAndParams.getParams().toArray());
        page.setRecords(recordList!=null?recordList: Collections.emptyList());
        return page;
    }


    /**
     * 批量插入
     * @param list
     * @return
     */
    @Override
    public int[] batchSave(List<T> list){
        SqlAndParams sqlAndParams = SqlGenerator.generateBatchSaveSqlByList(entityType,list);
        System.err.println("【batchSave】sqlAndParams=="+ JSON.toJSONString(sqlAndParams));
        return jdbcTemplate.batchUpdate(sqlAndParams.getSql(), (List<Object[]>) sqlAndParams.getParams());
    }

    /**
     * 保存或者更新，如果bean id为为空 更新
     * @param entity
     * @return
     */
    @Override
    public int saveOrUpdate(Object entity){
        return 0;
    }


    /**
     * 查询 遇到列的第一列数据
     * @return
     */
    protected RowMapper<T> oneColumnRowMapper(String... columns) {
        return (ResultSet rs, int rowNum) -> {
            try {
                PropertyAndColumnInfo propertyAndColumnInfo = MetaDataOperator.getPropertyAndColumnInfo(entityType,columns[0]);
                Object value = DbCommonUtil.getValueByFieldFromResultSet(columns[0], propertyAndColumnInfo.getJavaType(), rs);
                return (T)value;
            } catch (Exception e) {
                throw new RuntimeException("Error mapping row to oneColumn", e);
            }
        };
    }



    /**
     * 查询指定列数据
     * @param columns
     * @return
     */
    protected RowMapper<T> entityRowMapper(String... columns) {
        return (ResultSet rs, int rowNum) -> {
            try {
                Object entity = entityType.getDeclaredConstructor().newInstance();
                // 假设有一个方法可以从ResultSet中填充实体属性
                DbCommonUtil.setObjectFromResultSetByRow(rs, entity,columns);
                return (T)entity;
            } catch (Exception e) {
                throw new RuntimeException("Error mapping row to entity", e);
            }
        };
    }

    protected RowMapper<T> entityRowMapper() {
        return (ResultSet rs, int rowNum) -> {
            try {
                T entity = entityType.getDeclaredConstructor().newInstance();
                // 假设有一个方法可以从ResultSet中填充实体属性
                DbCommonUtil.setObjectFromResultSetByRow(rs, entity);
                return entity;
            } catch (Exception e) {
                throw new RuntimeException("Error mapping row to entity", e);
            }
        };
    }

}
